aboutsummaryrefslogtreecommitdiff
path: root/src/app/(main)/websites/[websiteId]/(reports)/attribution/Attribution.tsx
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-01-24 13:09:50 +0000
committerFuwn <[email protected]>2026-01-24 13:09:50 +0000
commit396acf3bbbe00a192cb0ea0a9ccf91b1d8d2850b (patch)
treeb9df4ca6a70db45cfffbae6fdd7252e20fb8e93c /src/app/(main)/websites/[websiteId]/(reports)/attribution/Attribution.tsx
downloadumami-main.tar.xz
umami-main.zip
Initial commitHEADmain
Created from https://vercel.com/new
Diffstat (limited to 'src/app/(main)/websites/[websiteId]/(reports)/attribution/Attribution.tsx')
-rw-r--r--src/app/(main)/websites/[websiteId]/(reports)/attribution/Attribution.tsx128
1 files changed, 128 insertions, 0 deletions
diff --git a/src/app/(main)/websites/[websiteId]/(reports)/attribution/Attribution.tsx b/src/app/(main)/websites/[websiteId]/(reports)/attribution/Attribution.tsx
new file mode 100644
index 0000000..264923a
--- /dev/null
+++ b/src/app/(main)/websites/[websiteId]/(reports)/attribution/Attribution.tsx
@@ -0,0 +1,128 @@
+import { Column, Grid } from '@umami/react-zen';
+import { LoadingPanel } from '@/components/common/LoadingPanel';
+import { Panel } from '@/components/common/Panel';
+import { SectionHeader } from '@/components/common/SectionHeader';
+import { useMessages, useResultQuery } from '@/components/hooks';
+import { ListTable } from '@/components/metrics/ListTable';
+import { MetricCard } from '@/components/metrics/MetricCard';
+import { MetricsBar } from '@/components/metrics/MetricsBar';
+import { percentFilter } from '@/lib/filters';
+import { formatLongNumber } from '@/lib/format';
+
+export interface AttributionProps {
+ websiteId: string;
+ startDate: Date;
+ endDate: Date;
+ model: string;
+ type: string;
+ step: string;
+ currency?: string;
+}
+
+export function Attribution({
+ websiteId,
+ startDate,
+ endDate,
+ model,
+ type,
+ step,
+ currency,
+}: AttributionProps) {
+ const { data, error, isLoading } = useResultQuery<any>('attribution', {
+ websiteId,
+ startDate,
+ endDate,
+ model,
+ type,
+ step,
+ });
+
+ const { formatMessage, labels } = useMessages();
+
+ const { pageviews, visitors, visits } = data?.total || {};
+
+ const metrics = data
+ ? [
+ {
+ value: visitors,
+ label: formatMessage(labels.visitors),
+ formatValue: formatLongNumber,
+ },
+ {
+ value: visits,
+ label: formatMessage(labels.visits),
+ formatValue: formatLongNumber,
+ },
+ {
+ value: pageviews,
+ label: formatMessage(labels.views),
+ formatValue: formatLongNumber,
+ },
+ ]
+ : [];
+
+ function AttributionTable({ data = [], title }: { data: any; title: string }) {
+ const attributionData = percentFilter(
+ data.map(({ name, value }) => ({
+ x: name,
+ y: Number(value),
+ })),
+ );
+
+ return (
+ <ListTable
+ title={title}
+ metric={formatMessage(currency ? labels.revenue : labels.visitors)}
+ currency={currency}
+ data={attributionData.map(({ x, y, z }: { x: string; y: number; z: number }) => ({
+ label: x,
+ count: y,
+ percent: z,
+ }))}
+ />
+ );
+ }
+
+ return (
+ <LoadingPanel data={data} isLoading={isLoading} error={error}>
+ {data && (
+ <Column gap>
+ <MetricsBar>
+ {metrics?.map(({ label, value, formatValue }) => {
+ return (
+ <MetricCard key={label} value={value} label={label} formatValue={formatValue} />
+ );
+ })}
+ </MetricsBar>
+ <SectionHeader title={formatMessage(labels.sources)} />
+ <Grid columns={{ xs: '1fr', md: '1fr 1fr' }} gap>
+ <Panel>
+ <AttributionTable data={data?.referrer} title={formatMessage(labels.referrer)} />
+ </Panel>
+ <Panel>
+ <AttributionTable data={data?.paidAds} title={formatMessage(labels.paidAds)} />
+ </Panel>
+ </Grid>
+ <SectionHeader title="UTM" />
+ <Grid columns={{ xs: '1fr', md: '1fr 1fr' }} gap>
+ <Panel>
+ <AttributionTable data={data?.utm_source} title={formatMessage(labels.sources)} />
+ </Panel>
+ <Panel>
+ <AttributionTable data={data?.utm_medium} title={formatMessage(labels.medium)} />
+ </Panel>
+ <Panel>
+ <AttributionTable data={data?.utm_cmapaign} title={formatMessage(labels.campaigns)} />
+ </Panel>
+ <Panel>
+ <AttributionTable data={data?.utm_content} title={formatMessage(labels.content)} />
+ </Panel>
+ <Panel>
+ <AttributionTable data={data?.utm_term} title={formatMessage(labels.terms)} />
+ </Panel>
+ </Grid>
+ </Column>
+ )}
+ </LoadingPanel>
+ );
+}